import { CDefaultBlueRate, CDefaultOrangeRate, CDefaultPurpleRate, CDownArea, CUpArea, CUpBlueRate, CUpgradeBlue, CUpgradeOrange, CUpgradePurple, CUpgradeRed, CUpgradeWhite, CUpOrangeRate, CUpPurpleRate } from "../../shared/common/Contsant";
import { EArea, EEntity, EQuality, EStatus } from "../../shared/common/Enum";
import { IEnemy, IGameData, ITower, IUser } from "../../shared/common/Interface";
import { Singleton } from "../../shared/framework/base/Singleton";
import { distanceSqu } from "../../shared/utils/MathUtil";
import { GameRoom } from "../runtime/GameRoom";
import { GameManager } from "../runtime/GameManager";
import { ExcelManager } from "../runtime/ExcelManager";
import { EnemyLogic } from "./EnemyLogic";
import { RandomUtils } from "../../framework/RandomUtils";
import { getSummonRate } from "../../shared/common/func";

/** 怪物逻辑 */
export class TowerLogic extends Singleton {

    public static get Ins() {
        return this.GetInstance<TowerLogic>()
    }

    loop(gameData: IGameData) {

        for (const tower of gameData.towers) {
            const { atkTag } = tower
            this.CD(tower, gameData.step)
            tower.status = EStatus.idle
            if (atkTag <= 0) {
                this.disTooFar(tower, gameData.enemies)
                this.searchEnemy(tower, gameData.enemies)
                this.atkEnemy(tower, gameData)
            }
        }
    }

    /** 寻找攻击目标 */
    searchEnemy(tower: ITower, enemies: IEnemy[]) {
        let { tarId } = tower
        if (tarId) {
            const enemy = enemies.find(v => v.id == tarId)
            if (!enemy || enemy.status == EStatus.dead) {
                this.findNearestEnemy(tower, enemies)
            }
        } else {
            this.findNearestEnemy(tower, enemies)
        }
    }

    /** 攻击怪物 */
    atkEnemy(tower: ITower, gameData: IGameData) {
        const { enemies, users } = gameData
        const { tarId, atkSpd, x } = tower
        if (tarId == 0) {
            return
        }
        tower.status = EStatus.atk
        tower.atkTag = 1 / atkSpd
        const enemy = enemies.find(v => v.id == tarId)
        if (enemy && enemy.status != EStatus.dead) {
            EnemyLogic.Ins.beHit(enemy, tower, users)
            tower.atkDir = x < enemy.x ? 0 : 1
        }
    }

    /** 获取塔攻击力 */
    getTowerAtkVal(tower: ITower, users: IUser[]) {

        const { entityType, atkVal } = tower
        ExcelManager.Ins.tableTower.init(entityType)
        const user = users.find(v => v.area == tower.area)

        let resAtkVal = 0
        if (user) {
            const { upgrade1level, upgrade2level, upgrade3level } = user
            switch (ExcelManager.Ins.tableTower.quality) {
                case EQuality.white:
                    resAtkVal += atkVal * CUpgradeWhite * (upgrade1level - 1)
                    break;
                case EQuality.blue:
                    resAtkVal += atkVal * CUpgradeBlue * (upgrade1level - 1)
                    break;
                case EQuality.purple:
                    resAtkVal += atkVal * CUpgradePurple * (upgrade2level - 1)
                    break;
                case EQuality.orange:
                    resAtkVal += atkVal * CUpgradeOrange * (upgrade3level - 1)
                    break;
                case EQuality.red:
                    resAtkVal += atkVal * CUpgradeRed * (upgrade3level - 1)
                    break;
            }
        }

        return resAtkVal + atkVal
    }

    /** 距离太远检测 */
    disTooFar(tower: ITower, enemies: IEnemy[]) {
        const { x: tx, y: ty, tarId } = tower
        if (tarId) {
            const enemy = enemies.find(v => v.id == tarId)
            if (enemy) {
                const { x, y } = enemy
                const tarDis = tower.atkDis ** 2
                const dis = distanceSqu(x, y, tx, ty)
                if (dis > tarDis) {
                    tower.tarId = 0
                }
            }
        }
    }

    /** 找到最近的怪 */
    findNearestEnemy(tower: ITower, enemies: IEnemy[]) {
        let tarDis = tower.atkDis ** 2
        tower.tarId = 0
        const { x: tx, y: ty } = tower
        for (const enemy of enemies) {
            const { x, y, id, status } = enemy
            const dis = distanceSqu(x, y, tx, ty)
            if (tarDis >= dis && status != EStatus.dead) {
                tarDis = dis
                tower.tarId = id
            }
        }
    }

    /** 生成一个防御塔 */
    generateTower(roomId: number, area: EArea, entityType: EEntity, index: [number, number]) {
        const cfg = ExcelManager.Ins.tableTower
        cfg.init(entityType)
        const atkVal = cfg.atkBase
        const atkSpd = cfg.spdBase
        const atkDis = cfg.atkDis
        const room = GameManager.Ins.getRoomById(roomId)
        const { x, y } = this.getTowerPos(area, index)
        this.getRandomTowerData()
        const tower: ITower = {
            atkDir: 0,
            atkVal,
            atkSpd,
            atkTag: 0,
            atkDis,
            criDmg: 1,
            criRat: 1,
            status: EStatus.born,
            id: room.getNextId(),
            area,
            x,
            y,
            tarId: 0,
            index,
            entityType,
        }
        room.addTower(tower)
    }

    /** 获取防御塔坐标 */
    getTowerPos(area: EArea, index: [number, number]) {

        let data = CUpArea
        if (area == EArea.down) {
            data = CDownArea
        }

        const x = data['x' + index[0]]
        const y = data['y' + index[1]]

        return { x, y }
    }

    CD(tower: ITower, step: number) {
        if (tower.atkTag >= 0) {
            tower.atkTag -= step
        }
    }

    /** 移除死亡塔 */
    removeDeadedTower(gameData: IGameData) {
        const towers = gameData.towers
        if (towers.length) {

            const deadTowers = []
            for (let i = towers.length - 1; i >= 0; i--) {
                const tower = towers[i]
                const { status, id, area, index } = tower
                if (status == EStatus.dead) {
                    towers.splice(i, 1)
                    deadTowers.push({ id, area, index })
                }
            }

            const room = GameManager.Ins.getRoomById(gameData.roomId)
            for (const deadTower of deadTowers) {
                const { id, area, index } = deadTower
                room.removeTower2map(area, index, id)
            }
        }
    }

    /** 生成待生成的塔 */
    generateMWaitTower(generateTower: { area: EArea, entity: EEntity, roomId: number }[]) {

        if (generateTower.length) {
            for (const data of generateTower) {
                const { roomId, area, entity } = data
                const index = this.checkIndex(entity, roomId, area)
                if (!index) return
                TowerLogic.Ins.generateTower(roomId, area, entity, index as [number, number])
            }
        }
    }

    /** 随机出一个塔数据 */
    getRandomTowerData() {
        const towerId = 1
        ExcelManager.Ins.tableTower.init(towerId)
    }

    /** 根据合成的塔获取合成后的塔 */
    getMergeTowerType(entity: EEntity) {
        ExcelManager.Ins.tableTower.init(entity)
        let quality = Number(ExcelManager.Ins.tableTower.quality)
        if (quality == 1) { quality = 3 } else { quality++ }
        return this.getRandomTowerByQuality(quality)
    }

    /** 通过品质随机获取一个塔 */
    getRandomTowerByQuality(quality: number) {
        const towerE2map: { [key: number]: EEntity[] } = {
            3: [EEntity.tower6, EEntity.tower7, EEntity.tower8, EEntity.tower9, EEntity.tower10],
            4: [EEntity.tower11, EEntity.tower12, EEntity.tower13, EEntity.tower14, EEntity.tower15],
            5: [EEntity.tower16, EEntity.tower17, EEntity.tower18, EEntity.tower19],
        }
        const index = RandomUtils.getRandomInt(0, towerE2map[quality].length, true, 1)
        return towerE2map[quality][index]
    }

    /** 空地检测 */
    checkIndex(entityType: EEntity, roomId: number, area: EArea) {
        const room = GameManager.Ins.getRoomById(roomId)
        const newIndex = this.getNewTowerIndex(room, area, entityType)
        return newIndex
    }

    /** 新建防御塔坐标 */
    getNewTowerIndex(room: GameRoom, area: EArea, entityType: EEntity) {

        for (let i = 1; i <= 6; i++) {
            for (let j = 1; j <= 3; j++) {
                const towers = room.towers[area]['' + i + j]
                if (towers && towers.length) {
                    if (
                        towers.length < 3 &&
                        towers[0].entityType == entityType
                    ) {
                        return [i, j]
                    }
                }
            }
        }

        for (let i = 1; i <= 6; i++) {
            for (let j = 1; j <= 3; j++) {
                const towers = room.towers[area]['' + i + j]
                if (!towers || !towers.length) {
                    return [i, j]
                }
            }
        }

        return null
    }

    /** 防御塔数量上限检测 */
    checkTowerNumMax(roomId: number, area: EArea, towerNumMax: number) {
        let towerNum = 0
        const room = GameManager.Ins.getRoomById(roomId)
        for (const tower of room.gameData.towers) {
            if (tower.area == area) {
                ++towerNum
                if (towerNum >= towerNumMax) {
                    return true
                }
            }
        }
        return false
    }

    /** 获取，召唤的塔的品质 */
    getSummonTowerQuality(level: number) {

        const orangeRate = getSummonRate(level, CUpOrangeRate, CDefaultOrangeRate)
        const purpleRate = getSummonRate(level, CUpPurpleRate, CDefaultPurpleRate) + orangeRate
        const blueRate = getSummonRate(level, CUpBlueRate, CDefaultBlueRate) + purpleRate

        const random = RandomUtils.getRandomFloat(0, 100)

        if (random <= orangeRate) return EQuality.orange
        else if (random <= purpleRate) return EQuality.purple
        else if (random <= blueRate) return EQuality.blue
        else return EQuality.white

    }
}